package com.fxu.framework.core.sql;

import cn.hutool.core.util.StrUtil;
import com.fxu.framework.core.util.FieldUtil;
import lombok.Data;
import lombok.ToString;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;

/**
 * 所有更新条件(包含查询条件)集中类
 * <p> 泛型: SE ,表示Entity实体类 </p>
 *
 * @author 方旭
 * @version 1.0.0
 */
@Data
@ToString
public class SUpdate<SE extends SEntity<?>> implements SCompare<SUpdate<SE>, SE> {
    /**
     * 实体类的类
     */
    protected Class<SE> clazz;

    /**
     * 数据库表唯一主键
     */
    protected String priKey;

    /**
     * 实体类的表名
     */
    protected String table;

    /**
     * 查询条件(会判断是否存在)
     */
    private List<SValue> queryList = new ArrayList<>();

    /**
     * 更新字段集合
     */
    private List<SValue> updateList = new ArrayList<>();

    /**
     * OR 查询条件(相同Key下的List必须至少两个)
     */
    private List<SChild<SE>> andOrList = new ArrayList<>();

    /**
     * 创建SQuery对象
     * @param <SE> SEntity对象类型
     * @param clazz SEntity类型对象
     * @return SQuery 对象
     */
    public static <SE extends SEntity<?>> SUpdate<SE> build(Class<SE> clazz) {
        return new SUpdate<>(clazz);
    }

    /**
     * 构造方法,设置实体类
     * @param clazz 实体类
     */
    public SUpdate(Class<SE> clazz) {
        this.clazz = clazz;
        this.priKey = FieldUtil.getPriKeyName(clazz);
    }

    /**
     * 构造方法,设置实体类
     */
    public SUpdate() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            this.clazz = (Class<SE>) ((ParameterizedType) type).getActualTypeArguments()[0];
            this.priKey = FieldUtil.getPriKeyName(clazz);
        } else {
            throw new RuntimeException("初始化错误!要么new SXxx<T>(){}，要么new SXxx<>(Class)");
        }
    }

    /**
     * 设置表名
     * @param table 表名
     * @return SUpdate 对象
     */
    public SUpdate<SE> table(String table) {
        if (StrUtil.isNotBlank(table)) {
            this.table = table;
        }
        return this;
    }

    /**
     * 设置查询ID
     * @param id 主键ID值
     * @return SUpdate 对象
     */
    public SUpdate<SE> id(Serializable id) {
        if (id != null) {
            this.where(SType.EQ, new SField<>(clazz, priKey), id);
        }
        return this;
    }

    /**
     * 设置查询ID集合
     * @param ids id集合
     * @return SQuery 对象
     */
    public SUpdate<SE> ids(Collection<? extends Serializable> ids) {
        // null则没有条件,如果是空,则1=2
        this.where(SType.IN, new SField<>(clazz, priKey), ids);
        return this;
    }

    /**
     * 或者 OR
     * select * from test 1=1 and (name = 'A' OR id = 1)
     * @param consumer 执行方法
     * @return 返回本对象
     */
    public SUpdate<SE> andOr(Consumer<SChild<SE>> consumer) {
        SChild<SE> sChild = new SChild<SE>(this.clazz){};
        consumer.accept(sChild);
        andOrList.add(sChild);
        return this;
    }

    /**
     * 增加值(update XXX set column = column + value)
     * @param column 字段
     * @param value 增加的值
     * @return SUpdate 对象
     */
    public SUpdate<SE> up(SFunc<SE, ?> column, Object value) {
        if (column != null) {
            updateList.add(new SValue(SType.UP, new SField<>(clazz, column), value));
        }
        return this;
    }

    /**
     * 增加值(update XXX set column = column + value)
     * @param column 字段
     * @param value 增加的值
     * @return SUpdate 对象
     */
    public SUpdate<SE> up(String column, Object value) {
        if (column != null) {
            updateList.add(new SValue(SType.UP, new SField<>(clazz, column), value));
        }
        return this;
    }

    /**
     * 减少值(update XXX set column = column - value)
     * @param column 字段
     * @param value 减少的值
     * @return SUpdate 对象
     */
    public SUpdate<SE> dn(SFunc<SE, ?> column, Object value) {
        if (column != null) {
            updateList.add(new SValue(SType.DN, new SField<>(clazz, column), value));
        }
        return this;
    }

    /**
     * 减少值(update XXX set column = column - value)
     * @param column 字段
     * @param value 减少的值
     * @return SUpdate 对象
     */
    public SUpdate<SE> dn(String column, Object value) {
        if (column != null) {
            updateList.add(new SValue(SType.DN, new SField<>(clazz, column), value));
        }
        return this;
    }

    /**
     * 增加值(update XXX set column = column + 1)
     * @param column 字段
     * @return SUpdate 对象
     */
    public SUpdate<SE> upOne(SFunc<SE, ?> column) {
        return up(column, 1);
    }

    /**
     * 减少值(update XXX set column = column - 1)
     * @param column 字段
     * @return SUpdate 对象
     */
    public SUpdate<SE> dnOne(SFunc<SE, ?> column) {
        return dn(column, 1);
    }

    /**
     * 设置值(update XXX set column = value)
     * @param column 字段
     * @param value 设置的值
     * @return SUpdate 对象
     */
    public SUpdate<SE> set(SFunc<SE, ?> column, Object value) {
        if (column != null) {
            updateList.add(new SValue(SType.SET, new SField<>(clazz, column), value));
        }
        return this;
    }

    /**
     * 设置值(update XXX set column = value)
     * @param column 字段
     * @param value 设置的值
     * @return SUpdate 对象
     */
    public SUpdate<SE> set(String column, Object value) {
        if (column != null) {
            updateList.add(new SValue(SType.SET, new SField<>(clazz, column), value));
        }
        return this;
    }
}
